01บทนำ · About This Guide
Test scope · deliverables · references
เอกสารนี้เป็น Test Documentation สำหรับหน้าจอ Subscribe Web v2.0 ครอบคลุม:
- Test Scenarios · 14 test areas — ครอบคลุมทุก flow ของ 6-step wizard
- Test Cases · 72 cases — Positive / Negative / Boundary / UI / Integration / A11y
- Playwright Automation Guide — POM · fixtures · sample scripts · CI
- Payment integration coverage — Omise · SlipOK · Bank Transfer · Trial lock
📌
Reference file:
ConstructQ_Subscribe.html · React SPA · standalone (no AppShell) · 6-step wizard · bilingual TH/EN · font size toggle · 4 packages (Trial/Starter/Pro/Enterprise) · 3 payment methods02Screen Overview
6-step wizard · 4 packages · 3 payment methods · TH/EN · font size
🗺️ Wizard Structure
| Step | Title (TH) | Title (EN) | Key Elements |
|---|---|---|---|
| 01 | ข้อกำหนดและเงื่อนไข | Terms & Conditions | Accordion (11 sections) · 2 checkboxes (T&C + PDPA) |
| 02 | เลือกแพ็คเก็จ | Choose Package | 4 plan cards (Trial/Starter/Pro/Enterprise) · billing cycle toggle (monthly/yearly) |
| 03 | ข้อมูลบริษัท | Company Details | Company name · tax ID (13 digits) · address + tambon autocomplete · contact · logo upload |
| 04 | ผู้ใช้งาน | Users | Add user · role dropdown (6 roles) · password rules · permission matrix (view-only) |
| 05 | ชำระเงิน | Payment | Duration stepper (months/years) · 3 tabs (Credit/QR/Bank) · summary · Trial-lock |
| 06 | ขอแสดงความยินดี | Welcome | Success message · order ref · sent-to email list · next steps |
💎 4 Packages
| Package | Monthly | Yearly | Users | Projects | Note |
|---|---|---|---|---|---|
| Trial | ฿0 | ฿0 | 5 | 1 | ทดลองใช้ · lock duration + payment |
| Starter | ฿3,900 | ฿42,900 | 10 | 3 | SME · save ฿3,900/yr |
| Professional | ฿7,900 | ฿86,900 | 30 | 15 | Most popular · save ฿7,900/yr |
| Enterprise | Custom | Custom | Unlimited | Unlimited | SSO · On-prem · SLA 99.9% |
💳 3 Payment Methods
- Credit Card — via Omise gateway · 4-field form (card number, name, expiry, CVC)
- PromptPay QR — QR code + slip upload · auto-verify via SlipOK ~30 sec
- Bank Transfer — Kasikorn Bank info + slip upload · manual verification 1 business hour
🎨 Additional UI Features
- Font size toggle — A- / A / A+ (13/15/17 px base)
- Language toggle — TH 🇹🇭 / EN 🇬🇧 · updates all labels + T&C content
- Brand mini header — ConstructQ logo · standalone page (no AppShell)
- Vertical stepper — left side · click-to-jump navigation
03Test Strategy
Test types · priority · risk-based approach
🎯 Test Types
| Type | Objective | Coverage |
|---|---|---|
| Positive | Happy path · Trial + all paid plans | ~40% |
| Negative | Invalid input · payment failure · duplicate | ~25% |
| Boundary | Tax ID digits · password rules · duration 1-60 | ~10% |
| Integration | Omise · SlipOK · Email · Autocomplete API | ~15% |
| UI/UX | Layout · responsive · animation · font size | ~7% |
| Accessibility | Keyboard · ARIA · contrast · screen reader | ~3% |
⚡ Priority
- P1 — Critical · payment · save · signup completion · data integrity
- P2 — High · validation · UX · Trial lock behavior
- P3 — Medium · UI polish · edge cases · font size · translations
🌐 Environments
- Dev/Staging: Omise TEST keys · SlipOK sandbox · MailHog for email capture
- UAT: Real Omise TEST · real Kasikorn PromptPay test QR · staging DB
- Production: Smoke only · no real charges · use test card 4242 4242 4242 4242
04Test Scenarios + Test Cases
14 areas · 72 detailed test cases
4.1 · 🏠 Landing + Navigation
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-01 | เข้าหน้า Subscribe (default TH) | 1. Navigate /subscribe | Standalone page · logo · TH/EN toggle · font size · Step 01 active · vertical stepper visible | P1 | Pos |
| TC-02 | Stepper click-to-jump | 1. เข้า Step 01 2. คลิก Step 03 ใน stepper |
Jump ไป Step 03 · state ยัง preserved · Step 01 marked done ถ้าผ่าน · Step 02 skipped shows warning | P2 | Pos |
| TC-03 | Back/Next buttons | 1. Step 02 · กด "ถัดไป" | Advance to Step 03 · scroll top · stepper updates active | P1 | Pos |
| TC-04 | Browser back preserves state | 1. Fill Step 03 2. Browser back 3. Forward |
Data ยังอยู่ · form pre-filled | P2 | Pos |
| TC-05 | Refresh page (page reload) | 1. Fill Step 03 2. F5 refresh |
Warning "จะสูญเสียข้อมูล" · หรือ localStorage restore | P2 | Neg |
4.2 · 📜 Step 01 · Terms & Conditions
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-06 | Accordion sections load | 1. เข้า Step 01 | แสดง 11 sections (นิยาม · การสมัคร · บริการ · ค่าธรรมเนียม · IP · PDPA · SLA · etc.) · ปิดหมด default | P2 | Pos |
| TC-07 | Accordion expand/collapse | 1. คลิก section 6 (ค่าธรรมเนียม) | Expand animation · แสดง content · icon rotate · คลิกอีกครั้ง collapse | P3 | UI |
| TC-08 | T&C checkbox required | 1. ไม่ติ๊ก T&C 2. กด "ยอมรับและถัดไป" |
Button disabled หรือ error · block advance | P1 | Neg |
| TC-09 | PDPA checkbox required | 1. ติ๊ก T&C · ไม่ติ๊ก PDPA 2. กด "ถัดไป" |
Button disabled · ต้องติ๊กทั้งคู่ | P1 | Neg |
| TC-10 | Both checked · advance | 1. ติ๊กทั้ง 2 กล่อง 2. "ถัดไป" |
Advance to Step 02 · state persist | P1 | Pos |
| TC-11 | T&C EN translation | 1. Toggle EN 2. Expand section |
Content เปลี่ยนเป็น EN · section titles update | P2 | Pos |
4.3 · 💎 Step 02 · Choose Package
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-12 | 4 plan cards render | 1. เข้า Step 02 | 4 cards (Trial · Starter · Pro · Enterprise) · Pro มี "ยอดนิยม" badge · ราคาแสดงถูก | P1 | Pos |
| TC-13 | Cycle toggle · monthly ↔ yearly | 1. คลิก "รายปี" | ราคาเปลี่ยน (Starter 3,900 → 42,900) · แสดง savings ฿3,900/yr | P1 | Pos |
| TC-14 | Trial price = 0 | 1. Trial monthly + yearly | ฿0 ทั้งคู่ · no savings shown | P2 | Bnd |
| TC-15 | Enterprise = ติดต่อทีมขาย | 1. Click Enterprise | Card shows "ติดต่อทีมขาย / Contact Sales" · no fixed price · button = "ติดต่อเรา" | P1 | Pos |
| TC-16 | Select package · highlight | 1. Click Starter card | Card highlighted (border + shadow) · other cards dim · "ถัดไป" enabled | P1 | Pos |
| TC-17 | Package bullets visible | 1. View any card | Bullets แสดง (5-10 items) · matches TH/EN language | P2 | Pos |
| TC-18 | Default selection (biz rule) | 1. เข้า Step 02 ครั้งแรก | Pro card selected default (or no selection · confirm expected behavior) | P3 | UI |
| TC-19 | No package selected · block advance | 1. ไม่เลือก package 2. "ถัดไป" |
Button disabled หรือ error prompt | P1 | Neg |
4.4 · 🏢 Step 03 · Company Details
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-20 | Required fields highlighted | 1. เข้า Step 03 | Company name · Tax ID · Address · Contact name · Email · Phone มี * indicator | P2 | UI |
| TC-21 | Tax ID must be 13 digits | 1. พิมพ์ "12345" | Error "เลขประจำตัวผู้เสียภาษีต้อง 13 หลัก" · block save | P1 | Neg |
| TC-22 | Tax ID valid · 13 digits | 1. พิมพ์ "0123456789012" | Accepted · no error · optional checksum validation | P1 | Pos |
| TC-23 | Tax ID reject non-numeric | 1. พิมพ์ "abc123" | ตัวอักษรถูก strip · เหลือ "123" | P2 | Neg |
| TC-24 | Contact email format | 1. อีเมล "not-email" | Error "รูปแบบอีเมลไม่ถูกต้อง" | P1 | Neg |
| TC-25 | Contact phone format | 1. Phone "02-123-4567" | Accept Thai landline · หรือ mobile 08x-xxxx-xxxx | P2 | Pos |
| TC-26 | Tambon autocomplete search | 1. พิมพ์ "ห้วยขวาง" ใน tambon field | Dropdown แสดง options · เลือก → auto-fill district/province/postal code | P1 | Int |
| TC-27 | Tambon · empty state | 1. พิมพ์ "xxxxx" | "ไม่พบข้อมูล — ลองพิมพ์คำอื่น" | P3 | Neg |
| TC-28 | Company logo upload | 1. Upload PNG 200KB | Preview shows · file size + name displayed · valid types PNG/JPG/SVG | P2 | Pos |
| TC-29 | Logo upload · oversized | 1. Upload 10 MB image | Error "ไฟล์ใหญ่เกิน 5 MB" · reject | P2 | Neg |
| TC-30 | Logo upload · invalid type | 1. Upload .exe | Error "รองรับเฉพาะ PNG/JPG/SVG" | P2 | Neg |
4.5 · 👥 Step 04 · Users + Roles
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-31 | Empty state · no users | 1. เข้า Step 04 | 'ยังไม่มีผู้ใช้งาน — กด "เพิ่มผู้ใช้งาน" เพื่อเริ่ม' · CTA | P3 | UI |
| TC-32 | Add user · valid | 1. name = "สมชาย" 2. email = "somchai@t.com" 3. password = "Str0ng!Pass" 4. phone = "0812345678" 5. role = "pm" |
User added · row displayed · delete icon | P1 | Pos |
| TC-33 | Password toggle show/hide | 1. Type password 2. Click 👁️ |
Toggle between password/text · label toggle "แสดง"/"ซ่อน" | P3 | UI |
| TC-34 | Password rules · min 8 char | 1. password = "1234" | Error "อย่างน้อย 8 ตัวอักษร" | P1 | Neg |
| TC-35 | Password rules · complexity tooltip | 1. Hover password field | Tooltip "ตัวพิมพ์ใหญ่ + เล็ก + ตัวเลข + สัญลักษณ์" | P3 | UI |
| TC-36 | Role dropdown · 6 options | 1. Open role dropdown | 6 roles: Organize Admin · PM · QC Manager · Inspector · Fixer/Sub · Executive | P2 | Pos |
| TC-37 | Role select · show permissions | 1. Select "qc_insp" | Right side matrix shows features accessible by Inspector role · view-only | P2 | Pos |
| TC-38 | Duplicate email · 2 users | 1. Add 2 users same email | Error/warning "อีเมลซ้ำ" | P1 | Neg |
| TC-39 | Users > package limit | 1. Starter (10 users) 2. Add 11th user |
Warning "เกินจำนวนที่แพ็คเก็จรองรับ" · block or upsell | P1 | Bnd |
| TC-40 | Delete user | 1. Click delete on row | Confirm modal · confirm → remove | P2 | Pos |
4.6 · 💳 Step 05 · Payment
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-41 | Duration stepper · default 1 | 1. เข้า Step 05 | Default 1 month (or 1 year if cycle=yearly) · +/- buttons | P1 | Pos |
| TC-42 | Duration + / - | 1. Click + 3 times | 1 → 2 → 3 → 4 · summary updates · price recalculates | P1 | Pos |
| TC-43 | Duration min = 1 | 1. Duration = 1 2. Click - |
- disabled · stays at 1 | P2 | Bnd |
| TC-44 | Duration max (upper bound) | 1. Type 999 | Cap at max (e.g. 60 months / 5 years) · warning | P2 | Bnd |
| TC-45 | Duration chip preset | 1. Click "6 months" chip | Duration = 6 · price = base × 6 | P2 | Pos |
| TC-46 | Summary shows all fields | 1. View summary | Package · cycle · base price · duration · subtotal · VAT 7% · total | P1 | Pos |
| TC-47 | Payment tab switch | 1. Click Credit → QR → Bank | Tabs switch · content changes · active state visible | P1 | Pos |
| TC-48 | Credit card · valid | 1. Card = "4242 4242 4242 4242" 2. Name = "SOMCHAI" 3. Exp = 12/28 4. CVC = 123 |
Accept · Omise TEST charge succeeds · loading spinner · advance | P1 | Int |
| TC-49 | Credit card · declined | 1. Card = "4000 0000 0000 0002" | Error "บัตรถูกปฏิเสธ" · retry option · no advance | P1 | Int |
| TC-50 | Credit card · invalid CVC | 1. CVC = "12" | Error "CVC ไม่ถูกต้อง" · client-side | P2 | Neg |
| TC-51 | Credit card · expired date | 1. Exp = "01/20" | Error "บัตรหมดอายุ" · client-side | P2 | Neg |
| TC-52 | PromptPay QR display | 1. Switch to QR tab | QR code image · amount overlay · countdown timer · slip upload area | P1 | Pos |
| TC-53 | Slip upload · SlipOK verify | 1. Upload valid slip JPG | Auto-verify within 30s · success badge · advance | P1 | Int |
| TC-54 | Slip upload · invalid amount | 1. Upload slip with wrong amount | SlipOK returns mismatch · error "ยอดโอนไม่ตรง" · re-upload | P1 | Neg |
| TC-55 | Bank transfer · display bank info | 1. Switch to Bank tab | Kasikorn Bank · HQ · account no · copy button | P1 | Pos |
| TC-56 | Bank · copy account no | 1. Click copy icon | Toast "คัดลอกแล้ว" · clipboard has value | P3 | UI |
| TC-57 | Bank slip upload · confirm | 1. Upload slip 2. กดยืนยัน |
Manual review notice "จะยืนยันภายใน 1 ชั่วโมง" · advance to Welcome | P1 | Pos |
4.7 · 🎉 Step 06 · Welcome
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-58 | Welcome screen renders | 1. Complete payment | Congratulations message · order reference · order date · sent-to email count | P1 | Pos |
| TC-59 | Invitation emails list | 1. View sent-to list | Shows all users added in Step 04 · icon per email | P2 | Pos |
| TC-60 | Next steps guidance | 1. View next-steps section | 3-4 step numbered list · "ตรวจสอบอีเมล · ตั้งรหัสผ่าน · เริ่มใช้งาน" | P2 | Pos |
| TC-61 | "เริ่มใช้งาน" button | 1. Click "เริ่มใช้งาน" | Redirect to /dashboard หรือ /login · session created | P1 | Pos |
4.8 · 🔒 Trial Lock Behavior
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-62 | Trial · duration stepper locked | 1. Select Trial 2. Go to Step 05 |
Duration = 30 days fixed · +/- buttons disabled · locked state visual | P1 | Pos |
| TC-63 | Trial · payment section hidden | 1. Trial in Step 05 | Payment tabs hidden or replaced with trial banner "ฟรี 30 วัน ไม่ต้องชำระเงิน" | P1 | Pos |
| TC-64 | Trial · direct advance to Welcome | 1. Trial · Step 05 2. Click "เริ่มใช้งาน" |
Skip payment · directly advance to Step 06 · no invoice | P1 | Pos |
4.9 · 🌐 Language Toggle TH/EN
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-65 | TH → EN · full page | 1. Click EN flag | All labels · stepper · T&C content · package names · buttons update | P1 | Pos |
| TC-66 | Preserve data on toggle | 1. Fill Step 03 2. Toggle EN 3. Back to TH |
Data intact · no reset | P1 | Pos |
4.10 · 🔤 Font Size
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-67 | A- / A / A+ toggle | 1. Click A- · A · A+ | Base font-size 13 / 15 / 17 px · all text scales · layout intact | P3 | A11y |
| TC-68 | Persist font size choice | 1. Choose A+ · refresh | Localstorage persist · A+ still active | P3 | UI |
4.11 · 🔐 Permission Matrix (view-only)
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-69 | Matrix expand/collapse | 1. Click phase heading | Expand/collapse animation · icon rotate | P3 | UI |
4.12 · 🔌 Payment Integration (mock)
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-70 | Omise webhook · confirm charge | 1. Complete payment 2. Backend receives webhook |
Order marked paid · invoice email sent · user activated | P1 | Int |
4.13 · 📱 Responsive
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-71 | Tablet 768px · stepper horizontal | 1. Resize to 768px | Stepper switches to horizontal scroll · content full width | P3 | UI |
4.14 · ♿ Accessibility
| TC ID | Scenario | Steps | Expected Result | Priority | Type |
|---|---|---|---|---|---|
| TC-72 | Keyboard nav · full flow | 1. Tab through Step 01→06 | Focus visible · logical order · Enter submits · no keyboard traps | P2 | A11y |
📊
Test Case Summary: รวม 72 test cases · P1 = 32 · P2 = 30 · P3 = 10 · Positive 34 · Negative 15 · Boundary 5 · Integration 6 · UI 9 · A11y 3
05Playwright Automation Guide
Setup · POM · fixtures · sample tests · CI/CD
🚀 Setup
- Install:
npm init playwright@latest· TypeScript · Chromium+Firefox+WebKit - Structure:
tests/subscribe/,pages/,fixtures/,mocks/ - Omise TEST mode: set
OMISE_PUBLIC_KEY=pkey_test_xxx· use test cards - SlipOK mock: intercept
/api/slipok/verify· return canned success/fail - Email capture: MailHog local ·
http://localhost:8025API to read messages
📁 Project Structure
treetests/subscribe/ ├── step01-terms.spec.ts ├── step02-package.spec.ts ├── step03-company.spec.ts ├── step04-users.spec.ts ├── step05-payment.spec.ts ├── step06-welcome.spec.ts ├── trial-lock.spec.ts ├── language.spec.ts ├── payment-integration.spec.ts ├── a11y.spec.ts └── e2e-full-flow.spec.ts pages/ ├── SubscribePage.ts # Main POM ├── StepPackage.ts ├── StepCompany.ts ├── StepUsers.ts ├── StepPayment.ts └── StepWelcome.ts fixtures/ ├── companies.json ├── users.json └── test-cards.json mocks/ ├── omise.mock.ts ├── slipok.mock.ts └── tambon.mock.ts playwright.config.ts
🎯 SubscribePage POM
TypeScriptimport { Page, Locator, expect } from '@playwright/test'; export class SubscribePage { readonly page: Page; readonly stepperItems: Locator; readonly btnNext: Locator; readonly btnBack: Locator; readonly langTh: Locator; readonly langEn: Locator; constructor(page: Page) { this.page = page; this.stepperItems = page.locator('.sub-step'); this.btnNext = page.getByRole('button', { name: /ถัดไป|Next/ }); this.btnBack = page.getByRole('button', { name: /ย้อนกลับ|Back/ }); this.langTh = page.locator('[data-lang="th"]'); this.langEn = page.locator('[data-lang="en"]'); } async goto() { await this.page.goto('/subscribe'); } async acceptTerms() { await this.page.getByLabel(/ยอมรับข้อกำหนดและเงื่อนไข/).check(); await this.page.getByLabel(/ยอมรับ.*PDPA/).check(); await this.btnNext.click(); } async selectPackage(id: 'trial' | 'starter' | 'pro' | 'enterprise') { await this.page.locator(`[data-package="${id}"]`).click(); await this.btnNext.click(); } async setCycle(cycle: 'monthly' | 'yearly') { await this.page.locator(`.sub-cycle-toggle button[data-cycle="${cycle}"]`).click(); } async fillCompany(data: { name: string; taxId: string; contactName: string; contactEmail: string; contactPhone: string; tambon: string; }) { const p = this.page; await p.getByLabel(/ชื่อบริษัท/).fill(data.name); await p.getByLabel(/เลขประจำตัวผู้เสียภาษี/).fill(data.taxId); await p.getByLabel(/ชื่อผู้ติดต่อ/).fill(data.contactName); await p.getByLabel(/อีเมลผู้ติดต่อ/).fill(data.contactEmail); await p.getByLabel(/เบอร์โทรผู้ติดต่อ/).fill(data.contactPhone); await p.getByLabel(/ตำบล/).fill(data.tambon); await p.locator('.sub-drop-item').first().click(); // pick 1st autocomplete await this.btnNext.click(); } async addUser(u: { name: string; email: string; phone: string; password: string; role: string; }) { await this.page.getByRole('button', { name: /เพิ่มผู้ใช้งาน/ }).click(); const last = this.page.locator('.sub-user-row').last(); await last.getByLabel(/ชื่อ-นามสกุล/).fill(u.name); await last.getByLabel(/อีเมล/).fill(u.email); await last.getByLabel(/เบอร์โทร/).fill(u.phone); await last.getByLabel(/รหัสผ่าน/).fill(u.password); await last.getByLabel(/บทบาท/).selectOption(u.role); } async payWithCard(card: { number: string; name: string; exp: string; cvc: string; }) { const p = this.page; await p.getByRole('tab', { name: /บัตรเครดิต/ }).click(); await p.getByLabel(/เลขบัตร/).fill(card.number); await p.getByLabel(/ชื่อบนบัตร/).fill(card.name); await p.getByLabel(/วันหมดอายุ/).fill(card.exp); await p.getByLabel(/CVC/).fill(card.cvc); await p.getByRole('button', { name: /ชำระเงิน|Pay/ }).click(); } }
✅ Sample Test · E2E Full Flow (Starter Monthly · Credit Card)
TypeScriptimport { test, expect } from '@playwright/test'; import { SubscribePage } from '../pages/SubscribePage'; test.describe('Subscribe · E2E', () => { test('TC-E2E-01 · Starter monthly + credit card · complete signup', async ({ page }) => { const sub = new SubscribePage(page); await sub.goto(); // Step 01 await sub.acceptTerms(); // Step 02 await sub.setCycle('monthly'); await sub.selectPackage('starter'); // Step 03 await sub.fillCompany({ name: 'บ.ธาร์ณัส จำกัด', taxId: '0105561234567', contactName: 'สมชาย ใจดี', contactEmail: 'somchai@tarnas.co.th', contactPhone: '0812345678', tambon: 'ห้วยขวาง' }); // Step 04 await sub.addUser({ name: 'สมชาย ใจดี', email: 'somchai@tarnas.co.th', phone: '0812345678', password: 'Str0ng!Pass', role: 'pm' }); await page.getByRole('button', { name: /ถัดไป/ }).click(); // Step 05 · Payment await sub.payWithCard({ number: '4242424242424242', name: 'SOMCHAI JAIDEE', exp: '12/28', cvc: '123' }); // Wait for Welcome await expect(page.getByText(/ขอแสดงความยินดี/)).toBeVisible({ timeout: 15000 }); await expect(page.getByText(/order.*ref/i)).toBeVisible(); }); test('TC-62 · Trial lock · duration stepper disabled', async ({ page }) => { const sub = new SubscribePage(page); await sub.goto(); await sub.acceptTerms(); await sub.selectPackage('trial'); await page.locator('.sub-step:nth-child(5)').click(); await expect(page.locator('.sub-duration-stepper-lg.is-locked')).toBeVisible(); await expect(page.locator('.sub-duration-stepper-lg .btn').first()).toBeDisabled(); }); test('TC-21 · Tax ID must be 13 digits', async ({ page }) => { const sub = new SubscribePage(page); await sub.goto(); await sub.acceptTerms(); await sub.selectPackage('starter'); await page.getByLabel(/เลขประจำตัวผู้เสียภาษี/).fill('12345'); await page.getByRole('button', { name: /ถัดไป/ }).click(); await expect(page.getByText(/13 หลัก/)).toBeVisible(); }); test('TC-65 · TH → EN language toggle', async ({ page }) => { const sub = new SubscribePage(page); await sub.goto(); await expect(page.getByText('ข้อกำหนดและเงื่อนไข')).toBeVisible(); await sub.langEn.click(); await expect(page.getByText('Terms & Conditions')).toBeVisible(); }); });
🎭 Mock Setup · Omise + SlipOK
TypeScript · Route Interception// mocks/omise.mock.ts export async function mockOmise(page: Page) { await page.route('**/api.omise.co/**', async route => { const body = route.request().postDataJSON(); if (body?.card?.number?.startsWith('4242')) { await route.fulfill({ status: 200, json: { id: 'chrg_test_success', status: 'successful', paid: true }}); } else if (body?.card?.number?.startsWith('4000')) { await route.fulfill({ status: 400, json: { object: 'error', code: 'card_declined', message: 'The card was declined.' }}); } }); } // mocks/slipok.mock.ts export async function mockSlipOk(page: Page, expectAmount: number) { await page.route('**/api/slipok/verify', async route => { const body = route.request().postDataJSON(); if (body.amount === expectAmount) { await route.fulfill({ status: 200, json: { verified: true, amount: expectAmount, ref: 'SLIP-OK-TEST' }}); } else { await route.fulfill({ status: 400, json: { verified: false, reason: 'amount_mismatch' }}); } }); }
💡
Best Practices: ใช้
getByRole, getByLabel ก่อน CSS · Trial lock ต้องทดสอบทุก paid path · Omise/SlipOK ใช้ mock ใน CI · MailHog ตรวจ invitation emails · Use accessible names (Thai + English fallback ด้วย regex OR)06Appendix
📌 Version History
- ConstructQ_Subscribe.html · source · standalone page · 6-step wizard
- v1.0 · earlier release (task #117)
- v2.0 · 13 ก.ค. 2569 · Refresh · 72 test cases · 14 areas · restructured · added Trial-lock + Font size + Permission Matrix + Integration coverage
🔗 References
- Playwright Docs:
https://playwright.dev - Omise Docs:
https://www.omise.co/docs - SlipOK Docs:
https://slipok.com/documents - Test cards (Omise):
4242 4242 4242 4242(success),4000 0000 0000 0002(declined) - MailHog:
https://github.com/mailhog/MailHog
📊 Excel Companion
ดูไฟล์ ConstructQ_Subscribe_TestCases_v2.0.xlsx คู่กัน · 4 sheets: Summary · Test Scenarios · Test Cases · Playwright Coverage